package com.jboltai.pptextract;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * Generates an HTML viewer for PPT slides using the PPTPageProcessor
 */
public class HtmlViewerGenerator {
    private static final Logger logger = LoggerFactory.getLogger(HtmlViewerGenerator.class);
    
    private final PPTPageProcessor processor;
    private final List<SlideInfo> slides = new ArrayList<>();
    
    /**
     * Class to store information about each slide
     */
    private static class SlideInfo {
        int number;
        String title;
        String textContent;
        List<String> mediaFiles = new ArrayList<>();
        
        SlideInfo(int number, String title, String textContent) {
            this.number = number;
            this.title = title;
            this.textContent = textContent;
        }
        
        void addMediaFile(String relativePath) {
            mediaFiles.add(relativePath);
        }
    }
    
    public HtmlViewerGenerator() {
        this.processor = new PPTPageProcessorImpl();
    }
    
    /**
     * Generate an HTML viewer for the given PPT file
     * 
     * @param pptFile PPT file to process
     * @param outputDir Directory to save the HTML viewer and media files
     * @throws IOException If an I/O error occurs
     */
    public void generateHtmlViewer(File pptFile, File outputDir) throws IOException {
        // Clear slides from any previous run
        slides.clear();
        
        // Create output directory if it doesn't exist
        if (!outputDir.exists()) {
            outputDir.mkdirs();
        }
        
        // Create media directory
        File mediaDir = new File(outputDir, "media");
        if (!mediaDir.exists()) {
            mediaDir.mkdirs();
        }
        
        // Process slides one by one
        processor.processSlideBySlide(pptFile, mediaDir, new PPTPageProcessor.SlideContentHandler() {
            @Override
            public void onSlideProcessed(int slideNumber, String title, String textContent, Map<String, File> mediaFiles) {
                logger.info("Processing slide {} for HTML viewer", slideNumber);
                
                // Create slide info
                SlideInfo slideInfo = new SlideInfo(slideNumber, title, textContent);
                
                // Add media files
                if (mediaFiles != null && !mediaFiles.isEmpty()) {
                    for (Map.Entry<String, File> entry : mediaFiles.entrySet()) {
                        String fileName = entry.getKey();
                        File mediaFile = entry.getValue();
                        
                        // Copy media file to the media directory with a more organized name
                        try {
                            String relativePath = "media/slide_" + slideNumber + "_" + fileName;
                            File destFile = new File(outputDir, relativePath);
                            
                            // Ensure parent directory exists
                            if (!destFile.getParentFile().exists()) {
                                destFile.getParentFile().mkdirs();
                            }
                            
                            // Copy the file
                            Files.copy(mediaFile.toPath(), destFile.toPath(), StandardCopyOption.REPLACE_EXISTING);
                            
                            // Add to slide info
                            slideInfo.addMediaFile(relativePath);
                            
                        } catch (IOException e) {
                            logger.error("Error copying media file: {}", e.getMessage());
                        }
                    }
                }
                
                // Add slide info to the list
                slides.add(slideInfo);
            }
        });
        
        // Generate HTML files
        generateHtmlFiles(outputDir);
        
        logger.info("HTML viewer generated at: {}", new File(outputDir, "index.html").getAbsolutePath());
    }
    
    private void generateHtmlFiles(File outputDir) throws IOException {
        // Generate index.html (main viewer)
        generateIndexHtml(outputDir);
        
        // Generate individual slide HTML files
        for (SlideInfo slide : slides) {
            generateSlideHtml(outputDir, slide);
        }
        
        // Copy CSS and JS files
        generateCssFile(outputDir);
        generateJsFile(outputDir);
    }
    
    private void generateIndexHtml(File outputDir) throws IOException {
        File indexFile = new File(outputDir, "index.html");
        
        try (FileWriter writer = new FileWriter(indexFile)) {
            writer.write("<!DOCTYPE html>\n");
            writer.write("<html lang=\"en\">\n");
            writer.write("<head>\n");
            writer.write("    <meta charset=\"UTF-8\">\n");
            writer.write("    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n");
            writer.write("    <title>ppt Viewer</title>\n");
            writer.write("    <link rel=\"stylesheet\" href=\"https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css\">\n");
            writer.write("    <link rel=\"stylesheet\" href=\"https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css\">\n");
            writer.write("    <link rel=\"stylesheet\" href=\"styles.css\">\n");
            writer.write("</head>\n");
            writer.write("<body>\n");
            writer.write("    <div class=\"container-fluid\">\n");
            writer.write("        <div class=\"row\">\n");
            writer.write("            <!-- Sidebar -->\n");
            writer.write("            <div class=\"col-md-3 sidebar\">\n");
            writer.write("                <h2>Slides</h2>\n");
            writer.write("                <div class=\"list-group\">\n");
            
            // Add slide links
            for (SlideInfo slide : slides) {
                String title = slide.title != null && !slide.title.isEmpty() ? slide.title : "Slide " + slide.number;
                writer.write("                    <a href=\"#\" class=\"list-group-item list-group-item-action\" data-slide=\"" + slide.number + "\">" + 
                            escapeHtml(title) + "</a>\n");
            }
            
            writer.write("                </div>\n");
            writer.write("            </div>\n");
            
            writer.write("            <!-- Main content -->\n");
            writer.write("            <div class=\"col-md-9 main-content\">\n");
            writer.write("                <div class=\"slide-controls\">\n");
            writer.write("                    <button id=\"prevSlide\" class=\"btn btn-primary\"><i class=\"fas fa-chevron-left\"></i> Previous</button>\n");
            writer.write("                    <span id=\"slideCounter\">Slide 1 of " + slides.size() + "</span>\n");
            writer.write("                    <button id=\"nextSlide\" class=\"btn btn-primary\">Next <i class=\"fas fa-chevron-right\"></i></button>\n");
            writer.write("                </div>\n");
            writer.write("                <div id=\"slideContent\" class=\"slide-content\">\n");
            writer.write("                    <!-- Slide content will be loaded here -->\n");
            writer.write("                </div>\n");
            writer.write("            </div>\n");
            writer.write("        </div>\n");
            writer.write("    </div>\n");
            
            writer.write("    <script src=\"https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js\"></script>\n");
            writer.write("    <script src=\"viewer.js\"></script>\n");
            writer.write("</body>\n");
            writer.write("</html>\n");
        }
    }
    
    private void generateSlideHtml(File outputDir, SlideInfo slide) throws IOException {
        File slideDir = new File(outputDir, "slides");
        if (!slideDir.exists()) {
            slideDir.mkdirs();
        }
        
        File slideFile = new File(slideDir, "slide_" + slide.number + ".html");
        
        try (FileWriter writer = new FileWriter(slideFile)) {
            writer.write("<div class=\"slide\">\n");
            
            // Title
            if (slide.title != null && !slide.title.isEmpty()) {
                writer.write("    <h2 class=\"slide-title\">" + escapeHtml(slide.title) + "</h2>\n");
            }
            
            // Text content
            if (slide.textContent != null && !slide.textContent.isEmpty()) {
                writer.write("    <div class=\"slide-text\">\n");
                writer.write("        <pre>" + escapeHtml(slide.textContent) + "</pre>\n");
                writer.write("    </div>\n");
            }
            
            // Media files
            if (!slide.mediaFiles.isEmpty()) {
                writer.write("    <div class=\"slide-media\">\n");
                writer.write("        <h4>Media Files</h4>\n");
                writer.write("        <div class=\"media-gallery\">\n");
                
                for (String mediaPath : slide.mediaFiles) {
                    String fileName = Paths.get(mediaPath).getFileName().toString();
                    
                    if (fileName.matches("(?i).*\\.(jpg|jpeg|png|gif|bmp)$")) {
                        // Image file
                        writer.write("            <div class=\"media-item\">\n");
                        writer.write("                <img src=\"../" + mediaPath + "\" alt=\"" + fileName + "\" class=\"img-fluid\">\n");
                        writer.write("                <div class=\"media-caption\">" + fileName + "</div>\n");
                        writer.write("            </div>\n");
                    } else if (fileName.matches("(?i).*\\.(mp4|avi|mov|wmv)$")) {
                        // Video file
                        writer.write("            <div class=\"media-item\">\n");
                        writer.write("                <video controls class=\"img-fluid\">\n");
                        writer.write("                    <source src=\"../" + mediaPath + "\" type=\"video/" + getVideoMimeType(fileName) + "\">\n");
                        writer.write("                    Your browser does not support the video tag.\n");
                        writer.write("                </video>\n");
                        writer.write("                <div class=\"media-caption\">" + fileName + "</div>\n");
                        writer.write("            </div>\n");
                    } else if (fileName.matches("(?i).*\\.(mp3|wav|ogg|m4a|wma)$")) {
                        // Audio file
                        writer.write("            <div class=\"media-item\">\n");
                        writer.write("                <audio controls>\n");
                        writer.write("                    <source src=\"../" + mediaPath + "\" type=\"audio/" + getAudioMimeType(fileName) + "\">\n");
                        writer.write("                    Your browser does not support the audio tag.\n");
                        writer.write("                </audio>\n");
                        writer.write("                <div class=\"media-caption\">" + fileName + "</div>\n");
                        writer.write("            </div>\n");
                    } else {
                        // Other file - just show a link
                        writer.write("            <div class=\"media-item\">\n");
                        writer.write("                <a href=\"../" + mediaPath + "\" target=\"_blank\" class=\"btn btn-outline-primary\">\n");
                        writer.write("                    <i class=\"fas fa-file\"></i> " + fileName + "\n");
                        writer.write("                </a>\n");
                        writer.write("            </div>\n");
                    }
                }
                
                writer.write("        </div>\n");
                writer.write("    </div>\n");
            }
            
            writer.write("</div>\n");
        }
    }
    
    private void generateCssFile(File outputDir) throws IOException {
        File cssFile = new File(outputDir, "styles.css");
        
        try (FileWriter writer = new FileWriter(cssFile)) {
            writer.write("body {\n");
            writer.write("    font-family: Arial, sans-serif;\n");
            writer.write("    background-color: #f8f9fa;\n");
            writer.write("}\n\n");
            
            writer.write(".sidebar {\n");
            writer.write("    background-color: #f0f0f0;\n");
            writer.write("    padding: 20px;\n");
            writer.write("    height: 100vh;\n");
            writer.write("    overflow-y: auto;\n");
            writer.write("    position: sticky;\n");
            writer.write("    top: 0;\n");
            writer.write("}\n\n");
            
            writer.write(".main-content {\n");
            writer.write("    padding: 20px;\n");
            writer.write("}\n\n");
            
            writer.write(".slide-controls {\n");
            writer.write("    display: flex;\n");
            writer.write("    justify-content: space-between;\n");
            writer.write("    align-items: center;\n");
            writer.write("    margin-bottom: 20px;\n");
            writer.write("}\n\n");
            
            writer.write(".slide-content {\n");
            writer.write("    background-color: white;\n");
            writer.write("    padding: 20px;\n");
            writer.write("    border-radius: 5px;\n");
            writer.write("    box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);\n");
            writer.write("    min-height: 400px;\n");
            writer.write("}\n\n");
            
            writer.write(".slide-title {\n");
            writer.write("    color: #333;\n");
            writer.write("    margin-bottom: 20px;\n");
            writer.write("    padding-bottom: 10px;\n");
            writer.write("    border-bottom: 1px solid #eee;\n");
            writer.write("}\n\n");
            
            writer.write(".slide-text pre {\n");
            writer.write("    white-space: pre-wrap;\n");
            writer.write("    font-family: inherit;\n");
            writer.write("    background-color: #f8f9fa;\n");
            writer.write("    padding: 15px;\n");
            writer.write("    border-radius: 5px;\n");
            writer.write("}\n\n");
            
            writer.write(".media-gallery {\n");
            writer.write("    display: flex;\n");
            writer.write("    flex-wrap: wrap;\n");
            writer.write("    gap: 15px;\n");
            writer.write("    margin-top: 15px;\n");
            writer.write("}\n\n");
            
            writer.write(".media-item {\n");
            writer.write("    max-width: 300px;\n");
            writer.write("    text-align: center;\n");
            writer.write("    margin-bottom: 15px;\n");
            writer.write("}\n\n");
            
            writer.write(".media-item img, .media-item video {\n");
            writer.write("    max-width: 100%;\n");
            writer.write("    max-height: 200px;\n");
            writer.write("    border: 1px solid #ddd;\n");
            writer.write("    border-radius: 5px;\n");
            writer.write("}\n\n");
            
            writer.write(".media-caption {\n");
            writer.write("    margin-top: 5px;\n");
            writer.write("    font-size: 0.9em;\n");
            writer.write("    color: #666;\n");
            writer.write("}\n");
        }
    }
    
    private void generateJsFile(File outputDir) throws IOException {
        File jsFile = new File(outputDir, "viewer.js");
        
        try (FileWriter writer = new FileWriter(jsFile)) {
            writer.write("document.addEventListener('DOMContentLoaded', function() {\n");
            writer.write("    let currentSlide = 1;\n");
            writer.write("    const totalSlides = " + slides.size() + ";\n");
            writer.write("    \n");
            writer.write("    // Load initial slide\n");
            writer.write("    loadSlide(currentSlide);\n");
            writer.write("    \n");
            writer.write("    // Previous slide button\n");
            writer.write("    document.getElementById('prevSlide').addEventListener('click', function() {\n");
            writer.write("        if (currentSlide > 1) {\n");
            writer.write("            currentSlide--;\n");
            writer.write("            loadSlide(currentSlide);\n");
            writer.write("        }\n");
            writer.write("    });\n");
            writer.write("    \n");
            writer.write("    // Next slide button\n");
            writer.write("    document.getElementById('nextSlide').addEventListener('click', function() {\n");
            writer.write("        if (currentSlide < totalSlides) {\n");
            writer.write("            currentSlide++;\n");
            writer.write("            loadSlide(currentSlide);\n");
            writer.write("        }\n");
            writer.write("    });\n");
            writer.write("    \n");
            writer.write("    // Sidebar slide links\n");
            writer.write("    document.querySelectorAll('.list-group-item').forEach(function(item) {\n");
            writer.write("        item.addEventListener('click', function(e) {\n");
            writer.write("            e.preventDefault();\n");
            writer.write("            const slideNumber = parseInt(this.getAttribute('data-slide'));\n");
            writer.write("            currentSlide = slideNumber;\n");
            writer.write("            loadSlide(currentSlide);\n");
            writer.write("        });\n");
            writer.write("    });\n");
            writer.write("    \n");
            writer.write("    // Function to load a slide\n");
            writer.write("    function loadSlide(slideNumber) {\n");
            writer.write("        // Update active slide in sidebar\n");
            writer.write("        document.querySelectorAll('.list-group-item').forEach(function(item) {\n");
            writer.write("            item.classList.remove('active');\n");
            writer.write("            if (parseInt(item.getAttribute('data-slide')) === slideNumber) {\n");
            writer.write("                item.classList.add('active');\n");
            writer.write("            }\n");
            writer.write("        });\n");
            writer.write("        \n");
            writer.write("        // Update slide counter\n");
            writer.write("        document.getElementById('slideCounter').textContent = 'Slide ' + slideNumber + ' of ' + totalSlides;\n");
            writer.write("        \n");
            writer.write("        // Update prev/next buttons\n");
            writer.write("        document.getElementById('prevSlide').disabled = (slideNumber === 1);\n");
            writer.write("        document.getElementById('nextSlide').disabled = (slideNumber === totalSlides);\n");
            writer.write("        \n");
            writer.write("        // Load slide content\n");
            writer.write("        fetch('slides/slide_' + slideNumber + '.html')\n");
            writer.write("            .then(response => response.text())\n");
            writer.write("            .then(html => {\n");
            writer.write("                document.getElementById('slideContent').innerHTML = html;\n");
            writer.write("            })\n");
            writer.write("            .catch(error => {\n");
            writer.write("                console.error('Error loading slide:', error);\n");
            writer.write("                document.getElementById('slideContent').innerHTML = '<div class=\"alert alert-danger\">Error loading slide content</div>';\n");
            writer.write("            });\n");
            writer.write("    }\n");
            writer.write("});\n");
        }
    }
    
    private String escapeHtml(String text) {
        return text.replace("&", "&amp;")
                  .replace("<", "&lt;")
                  .replace(">", "&gt;")
                  .replace("\"", "&quot;")
                  .replace("'", "&#39;");
    }
    
    private String getVideoMimeType(String fileName) {
        String extension = fileName.substring(fileName.lastIndexOf('.') + 1).toLowerCase();
        switch (extension) {
            case "mp4": return "mp4";
            case "webm": return "webm";
            case "ogg": return "ogg";
            default: return "mp4";  // Default
        }
    }
    
    private String getAudioMimeType(String fileName) {
        String extension = fileName.substring(fileName.lastIndexOf('.') + 1).toLowerCase();
        switch (extension) {
            case "mp3": return "mpeg";
            case "ogg": return "ogg";
            case "wav": return "wav";
            default: return "mpeg";  // Default
        }
    }
    
    public static void main(String[] args) {
        if (args.length < 2) {
            System.out.println("Usage: java -cp <classpath> com.jboltai.pptextract.HtmlViewerGenerator <input-ppt-file> <output-directory>");
            System.out.println("Example: java -cp jboltai_ppt_extract.jar com.jboltai.pptextract.HtmlViewerGenerator presentation.pptx ./viewer");
            System.exit(1);
        }

        String inputFilePath = args[0];
        String outputDirPath = args[1];
        
        File inputFile = new File(inputFilePath);
        File outputDir = new File(outputDirPath);

        if (!inputFile.exists() || !inputFile.isFile()) {
            logger.error("Input file does not exist or is not a file: {}", inputFilePath);
            System.exit(1);
        }

        HtmlViewerGenerator generator = new HtmlViewerGenerator();
        
        try {
            generator.generateHtmlViewer(inputFile, outputDir);
            logger.info("HTML viewer generation complete. Open index.html in a browser to view the presentation.");
        } catch (IOException e) {
            logger.error("Error generating HTML viewer: {}", e.getMessage(), e);
            System.exit(1);
        }
    }
}
